<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ChatGPT Interface</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/quasar@1.20/dist/quasar.min.css">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<div id="appper">
    <div class="layout-wrapper"> <!-- 包裹 q-layout 的 div -->
        <q-layout>
            <q-header class="bg-primary text-white">
                <q-toolbar>
                    <q-btn flat dense round @click="drawer = !drawer">
                        <q-icon name="menu" />
                    </q-btn>
                    <q-toolbar-title>
                        AI助手
                    </q-toolbar-title>
                    <q-btn flat dense round>
                        <q-icon name="more_vert" @click=""/>
                        <q-menu v-model="menuQ">
                            <q-list>
                                <q-item clickable v-ripple @click="toggleFullScreen">
                                    <q-item-section avatar>
                                        <q-icon name="fullscreen" />
                                    </q-item-section>
                                    <q-item-section>
                                        全屏
                                    </q-item-section>
                                </q-item>
                            </q-list>
                        </q-menu>
                    </q-btn>
                </q-toolbar>
            </q-header>

            <q-drawer v-model="drawer" side="left" bordered>
                <div class="q-pa-md q-gutter-sm flex justify-between">
                    <q-btn flat dense round @click="newChat"><q-icon name="add_comment" /></q-btn>
                    <q-btn flat dense round icon="cleaning_services" @click="clearChat" />
                </div>
                <q-list>
                    <q-item v-for="(chat, index) in chats" :key="index" clickable v-ripple @click="loadChat(index)" :class="{'selected-chat': index === currentChatIndex}">
                        <q-item-section avatar>
                            <q-icon name="chat" />
                        </q-item-section>
                        <q-item-section>
                            <q-item-label>{{ chat.title }}</q-item-label>
                        </q-item-section>
                        <q-item-section side>
                            <q-btn flat dense round @click.stop="toggleChatMenu(index)">
                                <q-icon name="more_vert" />
                            </q-btn>
                            <q-menu v-model="chat.menu">
                                <q-list>
                                    <q-item clickable v-ripple @click="customizeTitle(chat)">
                                        <q-item-section avatar>
                                            <q-icon name="edit" />
                                        </q-item-section>
                                        <q-item-section>
                                            自定义标题
                                        </q-item-section>
                                    </q-item>
                                    <q-item clickable v-ripple @click="deleteChat(index)">
                                        <q-item-section avatar>
                                            <q-icon name="delete" />
                                        </q-item-section>
                                        <q-item-section>
                                            删除
                                        </q-item-section>
                                    </q-item>
                                </q-list>
                            </q-menu>
                        </q-item-section>
                    </q-item>
                </q-list>
            </q-drawer>


        <q-page-container>
            <div class="chatgpt">
                <div class="messages-container">
                    <div class="messages">
                        <div v-for="(message, index) in formItem.messages" :key="index" :class="{'message-user': message.role === 'user', 'message-assistant': message.role !== 'user'}">
                            <div class="message-content" :class="{'message-user': message.role === 'user', 'message-assistant': message.role !== 'user'}">
                                <q-avatar :class="{'right': message.role === 'user', 'left': message.role !== 'user'}">
<!--                                  todo warnning  这个webflow 不支持不带（），所以webflow上是 getUserAvatar() -->
                                    <img :src="message.role === 'user' ? getUserAvatar : 'https://uploads-ssl.webflow.com/657c661418a503e0b43c9905/664781d921ff30411c47952a_%E6%99%BA%E8%83%BD%E5%8A%A9%E6%89%8B-copy.svg'" />
                                </q-avatar>
                                <div class="message-content-per" v-html="renderMarkdown(message.content)"></div>
                                <q-btn floating mini @click="copyMessage(index)" icon="content_copy" class="copy-button"></q-btn>
                            </div>
                        </div>
                    </div>
<!--                    <div class="recommendations">-->
<!--                        <div v-for="question in recommendedQuestions" :key="question" class="recommendation" @click="submitRecommendedQuestion(question)">-->
<!--                            <q-icon name="lightbulb_outline" class="recommendation-icon" />-->
<!--                            {{ question }}-->
<!--                        </div>-->
<!--                    </div>-->
                    <div class="messages-container-extending" style="height: 275px;width: 100%;">
                    </div>
                </div>




                <div class="qingkong" style="text-align: center">
                    <q-btn class="button" color="primary" @click="clearDialog">清空对话</q-btn>
                </div>
                <div class="form-container">

                    <q-form :model="formItem" class="form">
                        <q-form-item label="模型 ：">
                            <q-select v-model="formItem.model" :options="modelList" />
                        </q-form-item>
                        <q-form-item>
                            <q-input v-model="formItem.input" type="textarea" :rows="5" placeholder="请输入..." @keydown="onKeyDown" />
                        </q-form-item>
                        <q-form-item style="text-align: right;">
                            <q-btn class="button" @click="clearInput">清空输入</q-btn>
                            <q-btn class="button" color="primary" @click="submit" :loading="formItem.loading">提交</q-btn>
                        </q-form-item>
                    </q-form>
                </div>
            </div>
        </q-page-container>
    </q-layout>
</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/showdown/dist/showdown.min.js"></script>
<script src="https://wxserver.cards120.com/static/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar@1.20/dist/quasar.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

<script>
    new Vue({
        el: '#appper',
        components: {
            QForm: Quasar.components.QForm,
            QSelect: Quasar.components.QSelect,
            QInput: Quasar.components.QInput,
            QTimeline: Quasar.components.QTimeline,
            QTimelineEntry: Quasar.components.QTimelineEntry,
            QBtn: Quasar.components.QBtn,
            QCard: Quasar.components.QCard,
            QCardSection: Quasar.components.QCardSection,
            QMarkdown: Quasar.components.QMarkdown,
            QAvatar: Quasar.components.QAvatar,
            VueMarkdown: window['VueMarkdown']
        },
        methods: {
            submitRecommendedQuestion(question) {
                this.formItem.input = question;
                this.submit();
            },
            loadChat(index) {
                this.formItem.messages = this.chats[index].messages;
                this.currentChatIndex = index
            },
            toggleFullScreen() {
                const elem = document.documentElement;
                if (!document.fullscreenElement) {
                    if (elem.requestFullscreen) {
                        elem.requestFullscreen();
                    } else if (elem.mozRequestFullScreen) { // Firefox
                        elem.mozRequestFullScreen();
                    } else if (elem.webkitRequestFullscreen) { // Chrome, Safari and Opera
                        elem.webkitRequestFullscreen();
                    } else if (elem.msRequestFullscreen) { // IE/Edge
                        elem.msRequestFullscreen();
                    }
                } else {
                    if (document.exitFullscreen) {
                        document.exitFullscreen();
                    } else if (document.mozCancelFullScreen) { // Firefox
                        document.mozCancelFullScreen();
                    } else if (document.webkitExitFullscreen) { // Chrome, Safari and Opera
                        document.webkitExitFullscreen();
                    } else if (document.msExitFullscreen) { // IE/Edge
                        document.msExitFullscreen();
                    }
                }
                this.menuQ = false; // 关闭菜单
            },
            toggleChatMenu(index) {
                // alert(this.chats[index].menu)


                this.$set(this.chats[index], 'menu', !this.chats[index].menu);
            },
            renderMarkdown(markdownText) {
                const converter = new showdown.Converter({
                    extensions: [],
                    openLinksInNewWindow: true,
                    simplifiedAutoLink: true,
                    literalMidWordUnderscores: true,
                    strikethrough: true,
                    tables: true,
                    tablesHeaderId: true,
                    ghCodeBlocks: true,
                    tasklists: true,
                    smoothLivePreview: true,
                    simpleLineBreaks: true,
                    parseImgDimensions: true,
                    emoji: true,
                    underline: true,
                    highlight: function (code, lang) {
                        return hljs.highlightAuto(code, [lang]).value;
                    }
                });
                return converter.makeHtml(markdownText);
            },
            chooseColor(role) {
                switch (role) {
                    case 'user': return 'blue';
                    default: return 'green';
                }
            },
            clearDialog() {
                this.formItem.messages = [
                    {
                        role: 'assistant',
                        content: '您好，请问有什么可以帮到您？',
                    },
                ];
                this.saveCurrentChat();

            },
            clearInput() {
                this.formItem.input = '';
            },
            onKeyDown(event) {
                if (event.ctrlKey && event.keyCode === 13) {
                    this.submit();
                }
            },
            addMessage(newMessage) {
                this.$set(this.formItem.messages, this.formItem.messages.length, newMessage);
            },
            async submit() {
                if (!this.formItem.input) {
                    this.$q.notify({
                        message: '请输入',
                        color: 'negative',
                    });
                    return;
                } else {
                    this.formItem.loading = true;
                    this.addMessage({
                        role: 'user',
                        content: this.formItem.input,
                    });

                    let apiEndpoint = 'https://chatgpt.yinziming.com/api/openai/v1/chat/completions';

                    const requestOptions = {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'Accept': 'text/event-stream'
                        },
                        body: JSON.stringify({
                            messages: this.formItem.messages.slice(1, this.formItem.messages.length),
                            model: this.formItem.model
                        })
                    };

                    try {
                        const response = await fetch(apiEndpoint, requestOptions);
                        if (!response.ok) {
                            throw new Error('网络请求失败');
                        }

                        const reader = response.body.getReader();
                        const decoder = new TextDecoder('utf-8');
                        let buffer = '';
                        const readStream = async () => {
                            var done1 = false
                            while (!done1) {
                                let { done, value } = await reader.read();

                                buffer = buffer + decoder.decode(value, { stream: true });;
                                done1 = done
                            }
                            var chunk = buffer
                            console.log(chunk)
                            console.log(JSON.parse(chunk.replace(/data:/g, "")))
                            var content = JSON.parse(chunk.replace(/data:/g, "")).choices[0].message.content
                            console.log(content)
                            this.addMessage({
                                role: 'assistant',
                                content: content,
                            });
                            ({ done, value } = await reader.read());

                            reader.releaseLock();
                            this.formItem.input = ''
                            this.formItem.loading = false;
                            console.log('Stream complete');

                            // 保存当前会话内容
                            this.saveCurrentChat();
                        };

                        readStream();

                    } catch (error) {
                        console.error("请求错误", error);
                        this.$q.notify({
                            message: '请求失败',
                            color: 'negative',
                        });
                        this.formItem.loading = false;
                    }
                }
            },
            saveCurrentChat() {
                const currentIndex = this.currentChatIndex;
                if (currentIndex > -1) {
                    this.$set(this.chats, currentIndex, { title: this.chats[currentIndex].title, messages: [...this.formItem.messages] });
                }
                localStorage.setItem('chats', JSON.stringify(this.chats));
            },
            newChat() {
                this.$q.notify({
                    message: '新对话创建',
                    color: 'positive',
                });
                this.chats.unshift(
                    { title: '新会话'+'-'+new Date().toLocaleString(), menu: false , messages:[{
                            role: 'assistant',
                            content: '您好，请问有什么可以帮到您？',
                        }]
                    }

                );
                this.loadChat(0)
                localStorage.setItem('chats', JSON.stringify(this.chats));
            },
            clearChat() {
                this.$q.notify({
                    message: '所有对话已清理',
                    color: 'positive',
                });
                this.chats = [];
                if(this.chats.length===0){
                    this.chats.unshift({ title: '新会话'+new Date().toLocaleString(), menu: false , messages:[{
                            role: 'assistant',
                            content: '您好，请问有什么可以帮到您？',
                        }]
                    })
                }
                this.loadChat(0)
                // 删除之后
                localStorage.setItem('chats', JSON.stringify(this.chats));


            },
            customizeTitle(chat) {
                this.$q.dialog({
                    title: '自定义标题',
                    prompt: {
                        model: '',
                        type: 'text'
                    },
                    cancel: true,
                    persistent: true
                }).onOk(data => {
                    chat.title = data;
                    this.saveCurrentChat()
                });
            },
            deleteChat(index) {

                if (index > -1) {
                    this.chats.splice(index, 1);
                }
                this.$q.notify({
                    message: '会话已删除',
                    color: 'positive',
                });
                if(this.chats.length===0){
                    this.chats.unshift({ title: '新会话'+new Date().toLocaleString(), menu: false , messages:[{
                            role: 'assistant',
                            content: '您好，请问有什么可以帮到您？',
                        }]
                    })
                }
                this.loadChat(0)
                // 删除之后
                localStorage.setItem('chats', JSON.stringify(this.chats));
            }
        },
        data() {
            return {
                recommendedQuestions: [
                    '石锐博士最新研究进展？石锐博士最新研究进展？石锐博士最新研究进展？石锐博士最新研究进展？石锐博士最新研究进展？',
                    '信息中心主要职责有哪些？',
                    '如何联系石锐博士？'
                ],
                currentChatIndex:0,
                menuQ:false,
                formItem: {
                    messages: [
                        {
                            role: 'assistant',
                            content: '您好，请问有什么可以帮到您？',
                        }
                    ],
                    model: 'gpt-3.5-turbo',
                    input: '',
                    loading: false,
                },
                modelList: [
                    'gpt-3.5-turbo',
                    'gpt-4',
                    'gpt-4-32k',
                    'chatgml-6'
                ],
                drawer: false,
                menu: false,
                chatMenu: false,
                chats: [
                    // { title: '新会话', menu: false , messages:[{
                    //         role: 'assistant',
                    //         content: '您好，请问有什么可以帮到您？',
                    //     }]}
                ]
            };
        },
        mounted() {
            // 初始化或调用的代码
            // this.chats.push({ title: '新会话', menu: false , messages:[{
            //         role: 'assistant',
            //         content: '您好，请问有什么可以帮到您？',
            //     }]})


            const savedChats = localStorage.getItem('chats');
            if (savedChats) {
                this.chats = JSON.parse(savedChats);
            } else {
                this.newChat()
            }

            if(this.chats.length===0){
                this.chats.unshift({ title: '新会话'+new Date().toLocaleString(), menu: false , messages:[{
                        role: 'assistant',
                        content: '您好，请问有什么可以帮到您？',
                    }]
                })
            }
            // 如果有已经存在的会话，加载第一个会话的内容

            if (this.chats.length > 0) {
                this.formItem.messages = this.chats[0].messages;
            } else {
                this.formItem.messages = [];
            }
        }
    });
</script>

<style>
    .messages-container {
        height: 400px;
        overflow-y: auto;
        padding: 10px;
    }

    .messages {
        display: flex;
        flex-direction: column;
    }

    .message-content {
        display: flex;
        max-width: 70%;
        margin-bottom: 10px;
    }

    .message-user {
        align-items: flex-end;
        display: flex;
        justify-content: flex-end;
    }

    .message-assistant {
        align-items: flex-start;
        display: flex;
        justify-content: flex-start;
    }

    .message-content .message-content-per {
        padding: 8px;
        background-color: #f9f9f9;
        border-radius: 10px;
        border: 1px solid #ddd;
        margin: 0;
    }

    .q-avatar {
        margin-left: 10px;
        margin-right: 10px;
    }

    .q-avatar.right {
        order: 2;
    }

    .q-avatar.left {
        order: -1;
    }

    .chatgpt {
        border: 1px solid #ccc;
        background: #ffffff;
        position: relative;
        overflow: hidden;
        display: flex;
        flex-direction: column;
        height: 100%;
    }

    .form-container {
        padding: 10px;
        border-top: 1px solid #ccc;
    }

    .form {
        margin: 0;
    }

    pre, code {
        font-family: 'Fira Code', 'Consolas', 'Monaco', 'Andale Mono', 'Ubuntu Mono', monospace;
        font-size: 0.85em;
        color: #dcdcdc;
        background-color: #1e1e1e;
        border-radius: 5px;
        padding: 0.5em;
    }

    pre {
        margin: 0.5em 0;
        overflow: auto;
        line-height: 1.2;
        border: 1px solid #333;
    }

    code {
        display: block;
        white-space: pre-wrap;
        overflow-x: auto;
    }

    .inline-code {
        padding: 0.2em 0.4em;
        background-color: #272822;
        border-radius: 3px;
        color: #f8f8f2;
    }

    .message-assistant .message-content-per p {
        font-size: 0.85em;
    }

    .message-content-per {
        padding-bottom: 0px !important;
    }

    .chatgpt {
        display: flex;
        flex-direction: column;
        height: 100vh;
        border: 1px solid #ccc;
        background: #ffffff;
        position: relative;
        overflow: hidden;
    }

    .messages-container {
        flex: 1;
        overflow-y: auto;
        padding: 10px;
    }

    .form-container {
        padding: 10px;
        border-top: 1px solid #ccc;
    }
    .btn-style {
        flex: 1;
        margin: 0 5px;
        display: flex;
        justify-content: center;
        align-items: center;
        border: 1px solid #dcdcdc;
        border-radius: 20px;
        background-color: #f5f5f5;
    }
    .q-gutter-sm {
        display: flex;
        align-items: center;
    }
    .chatgpt {
        display: flex;
        flex-direction: column;
        height: 100vh;
        border: 1px solid #ccc;
        background: #ffffff;
        position: relative;
        overflow: hidden;
    }
    .messages-container {
        flex: 1;
        overflow-y: auto;
        padding: 10px;
    }
    .form-container {
        padding: 10px;
        border-top: 1px solid #ccc;
    }
    .form-container {
        position: fixed;
        bottom: 0;
        width: 100%;
        background: white;
        border-top: 1px solid #ddd;
    }


     .messages-container {
         height: 400px; /* 可根据需要调整高度 */
         overflow-y: auto;
         padding: 10px;
     }

    .messages {
        display: flex;
        flex-direction: column;
    }

    .message-content {
        display: flex;
        max-width: 70%;
        margin-bottom: 10px;
    }

    .message-user {
        align-items: flex-end;
        display: flex;
        justify-content: flex-end;
    }

    .message-assistant {
        align-items: flex-start;
        display: flex;
        justify-content: flex-start;
    }

    .message-content .message-content-per {
        padding: 8px;
        background-color: #f9f9f9;
        border-radius: 10px;
        border: 1px solid #ddd;
        margin: 0;
    }

    .q-avatar {
        margin-left: 10px;
        margin-right: 10px;
    }

    .q-avatar.right {
        order: 2;
    }

    .q-avatar.left {
        order: -1;
    }

    .chatgpt {
        border: 1px solid #ccc;
        background: #ffffff;
        position: relative;
        overflow: hidden;
        display: flex;
        flex-direction: column;
        height: 100%; /* 使 chatgpt 元素高度填满父容器 */
    }

    .form-container {
        padding: 10px;
        border-top: 1px solid #ccc;
    }

    .form {
        margin: 0;
    }

    /*chatgpt代码格式修正*/
    pre, code {
        font-family: 'Fira Code', 'Consolas', 'Monaco', 'Andale Mono', 'Ubuntu Mono', monospace;
        font-size: 0.85em; /* 减小字体大小 */
        color: #dcdcdc; /* 浅灰色文字，适合深色背景 */
        background-color: #1e1e1e; /* 深色背景 */
        border-radius: 5px;
        padding: 0.5em; /* 减少内边距 */
    }

    pre {
        margin: 0.5em 0; /* 调整上下外边距 */
        overflow: auto;
        line-height: 1.2; /* 更紧凑的行高 */
        border: 1px solid #333; /* 深色边框 */
    }

    code {
        display: block;
        white-space: pre-wrap;
        overflow-x: auto; /* 超出部分显示水平滚动条 */


    }



    /* 特别适用于行内代码的样式，如果有需要 */
    .inline-code {
        padding: 0.2em 0.4em; /* 减少内边距 */
        background-color: #272822; /* 略有差异的背景色以区分 */
        border-radius: 3px;
        color: #f8f8f2;
    }
    .message-assistant .message-content-per p {
        font-size: 0.85em; /* 减小字体大小 */
    }

    .message-content-per {
        padding-bottom: 0px!important;
    }
    .chatgpt {
        display: flex;
        flex-direction: column;
        height: 100vh;  /* 使用视口高度，确保占满整个屏幕 */
        border: 1px solid #ccc;
        background: #ffffff;
        position: relative;
        overflow: hidden;
    }

    .messages-container {
        flex: 1;  /* 允许这个容器增长以填充所有可用空间 */
        overflow-y: auto;  /* 当内容超过容器高度时显示滚动条 */
        padding: 10px;
    }

    .form-container {
        padding: 10px;
        border-top: 1px solid #ccc;  /* 顶部边界清晰可见 */
    }


    /*    */
    .message-content {
        position: relative;
        display: flex;
        align-items: center;
        min-height: 50px;

    }

    .message-content-per {
        flex-grow: 1;
        padding: 8px;
        background-color: #f9f9f9;
        border-radius: 10px;
        border: 1px solid #ddd;
        margin: 0 10px;
    }

    /* 默认助理消息，按钮在右侧 */
    .copy-button {
        position: absolute;
        right: 0;
        top: 0;
        transform: translateY(-100%);
        margin-top: -15px;
        margin-right: 8px;
        border-radius: 50%;
        background-color: #FFFFFF; /* 按钮背景颜色 */
        box-shadow: 0 2px 5px rgba(0,0,0,0.2); /* 添加阴影效果 */
        width: 0px; /* 按钮宽度 */
        height: 0px; /* 按钮高度 */
        display: flex;
        align-items: center;
        justify-content: center;
        opacity: 0;  /* 默认不可见 */
        transition: opacity 0.3s;  /* 平滑过渡效果 */

    }

    /* 用户消息，按钮在左侧 */
    .message-user .copy-button {
        left: 0;
        right: auto;
        transform: translateY(-100%);
    }

    .copy-button:hover {
        background-color: #e1e1e1; /* 鼠标悬停时的背景颜色 */
        transform: translateY(-110%) scale(1.1); /* 鼠标悬停时稍微放大并上移 */
    }
    .message-content:hover .copy-button {
        opacity: 0.3;  /* 悬浮时变为可见 */
    }
    .selected-chat {
        background-color: #e0f7fa; /* 浅蓝色 */
    }

    .qingkong .button {
        position: fixed;
        bottom: 27%;

        background: white;
        border-top: 1px solid #ddd;
    }

    .q-drawer {
        position: fixed;
        top: 0;
        bottom: 0;
    }

    .chatgpt {
        height: 100vh; /* 使 chatgpt 元素高度填满视口 */
        overflow: hidden;
        display: flex;
        flex-direction: column;
    }

    .messages-container {
        flex: 1; /* 允许该容器增长以填充所有可用空间 */
        overflow-y: auto; /* 当内容超过容器高度时显示滚动条 */
        padding: 10px;
    }

    .recommendations {
        border-top: 1px solid #ddd;
        padding: 10px;
        background-color: #f9f9f9;
    }

    .recommendation {
        padding: 8px;
        margin: 5px 0;
        background-color: #fff;
        border: 1px solid #ddd;
        border-radius: 5px;
        cursor: pointer;
        transition: background-color 0.3s;
    }

    .recommendation:hover {
        background-color: #f1f1f1;
    }

    .messages > .message-assistant {
        margin-top: 20px;
    }


/*    */
    .recommendations {
        border-top: 1px solid #ddd;
        padding: 10px;
        background-color: #f9f9f9;
        display: flex;
        flex-direction: column;
        align-items: stretch;
    }

    .recommendation {
        display: flex;
        align-items: center;
        padding: 8px;
        margin: 5px 0;
        background-color: #fff;
        border: 1px solid #ddd;
        border-radius: 5px;
        cursor: pointer;
        transition: background-color 0.3s;
        width: 100%;
        max-width: 600px; /* 使推荐框宽度与会话框一致 */
        box-shadow: 0 2px 5px rgba(0,0,0,0.1);
    }

    .recommendation-icon {
        margin-right: 8px; /* 图标与文本间距 */
        font-size: 24px; /* 调整图标大小 */
    }

    .recommendation-content  {
        flex-grow: 1;
        font-size: 11px; /* 调整字体大小 */

    }

    .recommendation:hover {
        background-color: #f1f1f1;
    }

    .recommendations {
        background-color: rgba(250,251,251,0);
    }

</style>
</body>
</html>
